<?php
declare(strict_types=1);

namespace App\Utils;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use Hyperf\Logger\Logger;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Redis\Redis;
use Hyperf\Utils\Context;

/**
 * @Description 后端一些工具方法类
 * @author wuxian
 * @since 2020-04-15
 */
class ServerUtil
{
    /**
     * @return string
     * @Description  生成订单号
     * @author wuxian
     * @since 2020-04-16
     */
    public static function orderNo(): string
    {
        //list($msec, $sec) = explode(' ', microtime());
        //$msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        return date('YmdHis').static::uniqueNum();
    }

    /**
     * @return string
     * @Description  生成唯一数
     * @author wuxian
     * @since 2020-04-16
     */
    public static function uniqueNum(): string
    {
        mt_srand();
        $uniqid = sprintf('%u', crc32(uniqid(strval(mt_rand()), true)));
        return $uniqid;
    }

    //传入整型生成一个随机码
    public static function cipher($num): string
    {
        $table =[
            0 => 's',
            1 => 'g',
            2 => 'f',
            3 => 'm',
            4 => 'w',
            5 => '7',
            6 => 'x',
            7 => '1',
            8 => 'o',
            9 => '0',
            10 => '6',
            11 => 'u',
            12 => '5',
            13 => 'a',
            14 => 'e',
            15 => 'b',
            16 => 'd',
            17 => 'z',
            18 => '9',
            19 => 'v',
            20 => '3',
            21 => '8',
            22 => '4',
            23 => 'n',
            24 => 'k',
            25 => '2',
            25 => 'j',
            26 => 'l',
            27 => 'i',
            28 => 'r',
            29 => 'p',
            30 => 'y',
            31 => 'c',
            32 => 't',
            33 => '2',
            34 => 'q',
            35 => 'h',
        ];
        $res = '';
        $b = floatval(10000000000 + $num);
        while ($b > 25) {
            $res = $table[$b % 26].$res;
            $b = floor($b / 26);
        }
        $res = $table[$b].$res;
    
        return $res;
    }


    //生成随机数
    public static function randomNum($min, $max): int
    {
        mt_srand();
        return mt_rand($min, $max);
    }


    //生成随机字符串
    public static function randomCode(int $len): string
    {
        $strs="1234567890qwertyuiopasdfghjklzxcvbnm";
        mt_srand();
        return substr(str_shuffle($strs), mt_rand(0, strlen($strs)-$len), $len);
    }

    //获取redis锁
    public static function getLock($key, $expires = 10)
    {
        $key = 'lock_'.$key;
        $token = uniqid();
        $container = ApplicationContext::getContainer();
        $redis = $container->get(Redis::class);
        $res = $redis->set($key, $token, ['NX', 'EX' => $expires]);
        if ($res) {
            $lock = [
                'key' => $key,
                'token'    => $token,
            ];
            return $lock;
        }
        return false;
    }

    //删除redis锁
    public static function delLock($lock)
    {
        $key = $lock['key'];
        $token    = $lock['token'];
        $container = ApplicationContext::getContainer();
        $redis = $container->get(Redis::class);
        $script = '
            if redis.call("GET", KEYS[1]) == ARGV[1] then
                return redis.call("DEL", KEYS[1])
            else
                return 0
            end
        ';
        return $redis->eval($script, [$key, $token], 1);
    }


    /**
     * 记录日志
     * @param $message  //日志描述
     * @param string $context  //日志的内容
     * @param string $context  //日志channel
     */
    public static function info($desc = '', $context = [], $name = 'log')
    {
        if (Context::has('co_trace_id')) {
            $trace_id = Context::get('co_trace_id', '');
        } else {
            $trace_id = static::uniqueNum();
            Context::set('co_trace_id', $trace_id);
        }
        $log = ApplicationContext::getContainer()->get(\Hyperf\Logger\LoggerFactory::class)->get($trace_id);
        $log->info($desc, $context);
    }

    /**
     * 获取今天的时间
     */
    public static function getTodayTime()
    {
        $start = strtotime(date("Y-m-d", time()));
        return [$start, $start + 86400 - 1];
    }

    /**
     * 获取今天初的时间
     */
    public static function getBeginTodayTime()
    {
        return mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('Y'));
    }

    /**
     * 获取本周初的时间
     */
    public static function getBeginWeekTime()
    {
        return mktime(0, 0, 0, (int) date("m"), (int) date("d") - (int) date("w") + 1, (int) date("Y"));
    }

    /**
     * 获取本月初的时间
     */
    public static function getBeginMonthTime()
    {
        return mktime(0, 0, 0, (int) date('m'), 1, (int) date('Y'));
    }



    /**
     * 计算自动审核延迟时间
     */
    public static function autoDedayTime($user_id)
    {
        $container = ApplicationContext::getContainer();
        $redis = $container->get(Redis::class);
        $day = \date('Ymd');
        $key_count = 'grabb_'.$day.'_'.$user_id;
        $count = $redis->get($key_count);
        if ($count > 30) {
            return static::randomNum(300, 1200);
        } elseif ($count > 10 && $count <= 30) {
            return static::randomNum(180, 300);
        } else {
            return static::randomNum(10, 180);
        }
    }


    /**
     * 随机获取电信联通移动手机号码
     * @return string
     * @throws \Exception
     */
    public static function getRandomPhone()
    {
        $prefix = [
            "134","135","136","137","138","139","150","151","152","157","158","159","187","188",
            "130","131","132","155","156","185","186","145",
            "133","153","180","181","189"
        ];

        return $prefix[array_rand($prefix, 1)].random_int(10, 99).'****'.random_int(10, 99);
    }


    /**
     * 简单的校验银行卡号码
     * @param $bank
     * @return bool
     */
    public static function checkBank($bank)
    {
        if (strlen($bank) < 16 || strlen($bank) > 19) {
            return false;
        }
        if (!is_numeric($bank)) {
            return false;
        }
        return true;
    }

    /**
     * 构造时间区间的sql条件
     * @param $startDate
     * @param $endDate
     * @param string $field
     * @return array
     */
    public static function buildSqlTimeRange($startDate, $endDate, $field = 'add_time')
    {
        $whereDate = [];
        if ($startDate) {
            $whereDate[] = [$field, '>=', strtotime($startDate)];
        }
        if ($endDate) {
            $whereDate[] = [$field, '<', strtotime($endDate)];
        }

        // endDate在startDate之前
        if ($startDate && $endDate && strtotime($endDate) <= strtotime($startDate)) {
            throw new BusinessException(ErrorCode::ERR_BUESSUS, '时间区间非法');
        }
        return $whereDate;
    }

    //AES加密
    public static function opensslEncrypt($data, $method = 'aes-256-cbc')
    {
        return \base64_encode(openssl_encrypt($data, $method, config('web.aes_key'), OPENSSL_RAW_DATA, config('web.aes_iv')));
    }

    //AES加密
    public static function opensslDecrypt($data, $method = 'aes-256-cbc')
    {
        return openssl_decrypt(\base64_decode($data), $method, config('web.aes_key'), OPENSSL_RAW_DATA, config('web.aes_iv'));
    }


}
